/**
 *                            License
 * THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS  
 * CREATIVE COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). 
 * THE WORK IS PROTECTED BY COPYRIGHT AND/OR OTHER APPLICABLE LAW.  
 * ANY USE OF THE WORK OTHER THAN AS AUTHORIZED UNDER THIS LICENSE OR  
 * COPYRIGHT LAW IS PROHIBITED.
 * 
 * BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND  
 * AGREE TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE  
 * MAY BE CONSIDERED TO BE A CONTRACT,
 * THE LICENSOR GRANTS YOU THE RIGHTS CONTAINED 
 * HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND CONDITIONS.
 * 
 */
package lineage.database.tables;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Map;

import lineage.core.L1GameClient;
import lineage.database.L1AbstractDatabase;
import lineage.database.tables.bean.L1Account;
import lineage.util.DateTimeUtil;
import lineage.util.PerformanceTimer;
import lineage.util.Util;
import lineage.util.collections.Maps;

/**
 * 账号资料表.
 * 
 * @version 2014年3月13日下午3:35:01
 * @author jrwz
 */
public final class AccountTable extends L1AbstractDatabase {
    private final Map<String, L1Account> list = Maps.newHashMap();

    /**
     * 静态初始化器，由JVM来保证线程安全.
     */
    private static class Holder {
        static AccountTable instance = new AccountTable();
    }

    /**
     * 取得该类的实例.
     */
    public static AccountTable getInstance() {
        return Holder.instance;
    }

    private AccountTable() {
        batch("SELECT * FROM accounts");
    }

    @Override
    protected void fillTable(final ResultSet rs) throws SQLException {
        final PerformanceTimer timer = new PerformanceTimer();
        final StringBuilder sb = new StringBuilder();
        sb.append("加载数据库：账号资料");

        while (rs.next()) {
            L1Account cha = new L1Account();
            cha.setAccountName(rs.getString("account"));
            cha.setPassword(rs.getString("password"));
            cha.setCharCount(rs.getInt("char_count"));
            cha.setRegisterDate(rs.getTimestamp("register_date"));
            cha.setRegisterIP(rs.getString("register_ip"));
            cha.setLastDate(rs.getTimestamp("last_date"));
            cha.setLastIP(rs.getString("last_ip"));
            put(cha); // 加入集合列表内
        }

        sb.append("(");
        sb.append(list.size());
        sb.append(")\t耗时 ");
        sb.append(timer.elapsedTimeMillis());
        sb.append(" 毫秒");
        Util.message(Util.SYSTEM_MESSAGE, sb.toString());
    }

    /**
     * 增加账号(写入数据库内).
     * 
     * @param client
     *            - 客户端对象
     * @param accountName
     *            - 账号名称
     * @param password
     *            - 密码
     * @return 如果增加成功则返回true
     */
    public boolean addAccount(final L1GameClient client, final String accountName, final String password) {
        boolean flag = false;
        final Timestamp ts = DateTimeUtil.getTimestampMillis();
        StringBuilder sb = new StringBuilder();
        sb.append("INSERT INTO accounts SET account='");
        sb.append(accountName);
        sb.append("', password='");
        sb.append(password);
        sb.append("', char_count='");
        sb.append(0);
        sb.append("', register_date='");
        sb.append(ts);
        sb.append("', register_ip='");
        sb.append(client.getIp());
        sb.append("', last_date='");
        sb.append(ts);
        sb.append("', last_ip='");
        sb.append(client.getIp());
        sb.append("'");

        final boolean isAdd = updateResult(sb.toString()); // 存入数据库内
        if (isAdd) {
            L1Account cha = new L1Account();
            cha.setAccountName(accountName);
            cha.setPassword(password);
            cha.setCharCount(0);
            cha.setRegisterDate(ts);
            cha.setRegisterIP(client.getIp().toString());
            cha.setLastDate(ts);
            cha.setLastIP(client.getIp().toString());
            putTo(cha); // 加入集合列表内

            sb = new StringBuilder();
            sb.append("(");
            sb.append(client.getIp());
            sb.append(")创建新账号：");
            sb.append("(");
            sb.append(accountName);
            sb.append(")");
            Util.message(Util.SYSTEM_MESSAGE, sb.toString());
            flag = true;
        }
        return flag;
    }

    /**
     * 删除账号(数据库内).
     * 
     * @param accountName
     *            - 要删除的账号名
     * @return 如果删除成功则返回true
     */
    public boolean delAccount(final String accountName) {
        boolean flag = false;
        StringBuilder sb = new StringBuilder();
        sb.append("DELETE FROM accounts WHERE account='");
        sb.append(accountName);
        sb.append("'");

        final boolean isDel = updateResult(sb.toString());
        if (isDel) {
            remove(accountName); // 从缓存中删除该账号

            sb = new StringBuilder();
            sb.append("删除账号：");
            sb.append("(");
            sb.append(accountName);
            sb.append(")");
            Util.message(Util.SYSTEM_MESSAGE, sb.toString());
            flag = true;
        }
        return flag;
    }

    /**
     * 更改密码(数据库内).
     * 
     * @param client
     *            - 客户端对象
     * @param password
     *            - 新密码
     * @return 如果修改成功则返回true
     */
    public boolean updatePassword(final L1GameClient client, final String password) {
        boolean flag = false;
        L1Account acc = getAccount(client.getAccountName());
        if (acc != null) {
            final StringBuilder sb = new StringBuilder();
            sb.append("UPDATE accounts SET password='");
            sb.append(password);
            sb.append("' WHERE account='");
            sb.append(acc.getAccountName());
            sb.append("'");

            boolean isUp = updateResult(sb.toString());
            if (isUp) {
                acc.setPassword(password);
                putTo(acc); // 修改集合列表的相应内容
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 更新最后登入的日期(数据库内).
     * 
     * @param client
     *            - 客户端对象
     * @param date
     *            - 要修改的日期(Timestamp对象)
     * @return 如果修改成功则返回true
     */
    public boolean updateLastDate(final L1GameClient client, final Timestamp date) {
        boolean flag = false;
        L1Account acc = getAccount(client.getAccountName());
        if (acc != null) {
            final StringBuilder sb = new StringBuilder();
            sb.append("UPDATE accounts SET last_date='");
            sb.append(date);
            sb.append("' WHERE account='");
            sb.append(acc.getAccountName());
            sb.append("'");

            boolean isUp = updateResult(sb.toString());
            if (isUp) {
                acc.setLastDate(date);
                putTo(acc); // 修改集合列表的相应内容
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 更新最后登入的ip地址(数据库内).
     * 
     * @param client
     *            - 客户端对象
     * @return 如果修改成功则返回true
     */
    public boolean updateLastIP(final L1GameClient client) {
        boolean flag = false;
        L1Account acc = getAccount(client.getAccountName());
        if (acc != null) {
            final StringBuilder sb = new StringBuilder();
            sb.append("UPDATE accounts SET last_ip='");
            sb.append(client.getIp());
            sb.append("' WHERE account='");
            sb.append(acc.getAccountName());
            sb.append("'");

            boolean isUp = updateResult(sb.toString());
            if (isUp) {
                acc.setLastIP(client.getIp().toString());
                putTo(acc); // 修改集合列表的相应内容
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 更新已创角色的总数量(数据库+缓存内).
     * 
     * @param client
     *            - 客户端对象
     * @param count
     *            - 要设置的数量
     * @return 如果修改成功则返回true
     */
    public boolean updateCharCount(final L1GameClient client, final int count) {
        boolean flag = false;
        L1Account acc = getAccount(client.getAccountName());
        if (acc != null) {
            final StringBuilder sb = new StringBuilder();
            sb.append("UPDATE accounts SET char_count='");
            sb.append(count);
            sb.append("' WHERE account='");
            sb.append(acc.getAccountName());
            sb.append("'");

            boolean isUp = updateResult(sb.toString());
            if (isUp) {
                acc.setCharCount(count);
                putTo(acc); // 修改集合列表的相应内容
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 根据帐号名取得该帐号下已创角色的总数量(缓存内).
     * 
     * @param accountName
     *            - 帐号名
     * @return 如果没找到或出错则返回0
     */
    public int getCharCount(final String accountName) {
        if (list.containsKey(accountName)) {
            return list.get(accountName).getCharCount();
        }
        return 0;
    }

    /**
     * 检查是否有此账号(数据库内).
     * 
     * @param accountName
     *            - 账号名称
     * @return 有则返回true
     */
    public boolean isAccount(final String accountName) {
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT * FROM accounts WHERE account='");
        sb.append(accountName);
        sb.append("'");
        return getSingleBoolean(sb.toString());
    }

    /**
     * 检查是否有此账号(缓存内) - 应尽量用此方法以节省资源.
     * 
     * @param accountName
     *            - 账号名称
     * @return 有则返回true
     */
    public boolean isAccountList(final String accountName) {
        boolean flag = false;
        if (list.containsKey(accountName)) {
            flag = true;
        }
        return flag;
    }

    /**
     * 检查是否能登入(数据库内).
     * 
     * @param accountName
     *            - 账号名称
     * @param password
     *            - 密码
     * @return 如果账号与密码全对应则判断为true(可以登入)
     */
    public boolean isLogin(final String accountName, final String password) {
        StringBuilder sb = new StringBuilder();
        sb.append("SELECT * FROM accounts WHERE account='");
        sb.append(accountName);
        sb.append("' AND password='");
        sb.append(password);
        sb.append("'");
        return getSingleBoolean(sb.toString());
    }

    /**
     * 检查是否能登入(缓存内) - 应尽量用此方法以节省资源.
     * 
     * @param accountName
     *            - 账号名称
     * @param password
     *            - 密码
     * @return 如果账号与密码全对应则判断为true(可以登入)
     */
    public boolean isLoginList(final String accountName, final String password) {
        boolean flag = false;
        if (list.containsKey(accountName)) {
            if (list.get(accountName).getPassword().equalsIgnoreCase(password)) {
                flag = true;
            }
        }
        return flag;
    }

    /**
     * 根据账号名取得L1Account对象.
     * 
     * @param accountName
     *            - 账号名称
     * @return L1Account对象(如果找不到则返回null)
     */
    public L1Account getAccount(final String accountName) {
        L1Account account = null;
        if (list.containsKey(accountName)) {
            account = list.get(accountName);
        }
        return account;
    }

    /**
     * 取得缓存列表.
     * 
     * @return 列表中的所有元素
     */
    public Map<String, L1Account> get() {
        return list;
    }

    /**
     * 取得缓存列表.
     * 
     * @return 列表中的所有元素
     */
    public Collection<L1Account> getList() {
        return list.values();
    }

    /**
     * 将新元素加入集合列表.
     * 
     * @param cha
     *            - L1Account对象
     */
    public void put(final L1Account cha) {
        list.put(String.valueOf(cha.getAccountName()), cha);
    }

    /**
     * 将元素的部分内容追加入集合列表.
     * 
     * @param cha
     *            - L1Account对象
     */
    public void putTo(final L1Account cha) {
        cha.setAccountName(cha.getAccountName());
        cha.setPassword(cha.getPassword());
        cha.setCharCount(cha.getCharCount());
        cha.setRegisterDate(cha.getRegisterDate());
        cha.setRegisterIP(cha.getRegisterIP());
        cha.setLastDate(cha.getLastDate());
        cha.setLastIP(cha.getLastIP());
        put(cha);
    }

    /**
     * 从缓存列表中删除指定账号(根据帐号名).
     * 
     * @param accountName
     *            - 要删除账号的名称
     */
    public void remove(final String accountName) {
        if (list.containsKey(accountName)) {
            list.remove(accountName);
        }
    }
}
